package dtaskboard.server;

import java.util.Collection;
import java.util.Date;
import java.util.HashSet;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import dtaskboard.client.dto.LoginDTO;
import dtaskboard.client.dto.RoleClass;
import dtaskboard.client.dto.RoleDTO;
import dtaskboard.client.exception.EntityNotFoundException;
import dtaskboard.client.exception.LoginDeniedException;
import dtaskboard.client.exception.PasswordMismatchException;
import dtaskboard.client.exception.UnauthorizedException;
import dtaskboard.client.service.LoginService;
import dtaskboard.entities.Project;
import dtaskboard.entities.Role;
import dtaskboard.entities.User;
import dtaskboard.server.dao.ProjectDao;
import dtaskboard.server.dao.RoleDao;
import dtaskboard.server.dao.UserDao;
import dtaskboard.server.util.SecurityUtil;

public class LoginServiceImpl extends RemoteServiceServlet implements
    LoginService {

  /**
   * 
   */
  private static final long serialVersionUID = -8254269901889851842L;

  @Override
  public String login(String login, String password) {
    UserDao userDao = new UserDao();
    if (!userDao.authenticate(login, password)) {
      if (userDao.list().size() == 0 && "admin".equals(login)) {
        User admin = new User();
        admin.setLogin("admin");
        admin.setPassword(password);
        admin.setName("Administrador");

        RoleDao roleDao = new RoleDao();

        Role adminRole = new Role();
        adminRole.setRoleClass(RoleClass.ADMIN);
        roleDao.save(adminRole);

        admin.getRoles().add(adminRole);
        userDao.save(admin);
        return this.saveSession(userDao.find(login));
      }
      throw new LoginDeniedException();
    }

    return this.saveSession(userDao.find(login));
  }

  @Override
  public void logout(String sessionId) {
    SessionManager.get().clean(sessionId);
  }

  @Override
  public boolean isAuthenticated(String sessionId) {
    if (SessionManager.get().userId(sessionId) != null) {
      return true;
    }
    return false;
  }

  private String saveSession(User user) {
    String sessionId = user.getLogin() + new Date().toString();
    SessionManager.get().add(user, sessionId);
    return sessionId;
  }

  @Override
  public Collection<RoleDTO> getUserRoles(String sessionId) {
    User user = SessionManager.get().userId(sessionId);
    Collection<RoleDTO> roles = new HashSet<RoleDTO>();
    for (Role r : user.getRoles()) {
      String projectName =
          (r.getProject() == null) ? null : r.getProject().getName();
      roles.add(new RoleDTO(r.getRoleClass(), projectName));
    }

    return roles;
  }

  @Override
  public void saveUser(String username, String password, String name,
      String sessionId) {
    if (!SecurityUtil.hasAdmin(sessionId)) {
      throw new UnauthorizedException();
    }

    User u = new User();
    u.setName(name);
    u.setLogin(username);
    u.setPassword(password);

    UserDao userDao = new UserDao();
    userDao.save(u);
  }

  @Override
  public void addRoleToUser(String username, RoleClass role,
      String projectName, String sessionId) {
    if (!SecurityUtil.hasAdmin(sessionId)) {
      throw new UnauthorizedException();
    }
    ProjectDao projDao = new ProjectDao();
    Project p = projDao.findByName(projectName);
    if (p == null) {
      throw new EntityNotFoundException("project");
    }
    UserDao userDao = new UserDao();
    User user = userDao.find(username);
    if (user == null) {
      throw new EntityNotFoundException("user");
    }
    Role r = new Role();
    r.setRoleClass(role);
    r.setProject(p);

    RoleDao roleDao = new RoleDao();
    roleDao.save(r);
    user.getRoles().add(r);
    userDao.update(user);

  }

  @Override
  public LoginDTO getLoginDTO(String sessionId) {
    User user = SessionManager.get().userId(sessionId);
    Collection<RoleDTO> roles = new HashSet<RoleDTO>();
    for (Role r : user.getRoles()) {
      String projectName =
          (r.getProject() == null) ? null : r.getProject().getName();
      roles.add(new RoleDTO(r.getRoleClass(), projectName));
    }

    LoginDTO dto = new LoginDTO();
    dto.setLogin(user.getLogin());
    dto.setRoles(roles);
    return dto;
  }

  public void changePassword(String oldPass, String newPass, String sessionId) {
    User user = SessionManager.get().userId(sessionId);
    if (!oldPass.equals(user.getPassword())) {
      throw new PasswordMismatchException();
    }
    user.setPassword(newPass);
    new UserDao().update(user);
    SessionManager.get().add(user, sessionId);
  }
}
